home *** CD-ROM | disk | FTP | other *** search
- #!/bin/sh
- # This script sets up an ecryptfs mount in a user's ~/Private
- #
- # Originally ecryptfs-setup-pam-wrapped.sh by Michael Halcrow, IBM
- #
- # Ported for use on Ubuntu by Dustin Kirkland <kirkland@canonical.com>
- # Copyright (C) 2008 Canonical Ltd.
- # Copyright (C) 2007-2008 International Business Machines
- PRIVATE_DIR="Private"
- WRAPPING_PASS="LOGIN"
- ECRYPTFS_DIR="/home/.ecryptfs"
- PW_ATTEMPTS=3
- TEXTDOMAIN="ecryptfs-utils"
- MESSAGE=`gettext "Enter your login passphrase"`
- CIPHER="aes"
- KEYBYTES="16"
- FNEK=
-
- # Zero out user-defined GREP_OPTIONS, such as --line-number
- GREP_OPTIONS=
-
- usage() {
- echo "
- Usage:
-
- $0 [-f|--force] [-w|--wrapping] [--nopwcheck] [-n|--no-fnek]
- [-u|--username USER] [-l|--loginpass LOGINPASS]
- [-m|--mountpass MOUNTPASS]
-
- -f, --force Force overwriting of an existing setup
- -w, --wrapping Use an independent wrapping passphrase,
- different from the login passphrase
- -n, --no-fnek Do not encrypt filenames; If this flag is
- omitted, and the kernel supports filename
- encryption, then filenames will be encrypted
- -u, --username Username for encrypted private mountpoint,
- defaults to yourself
- -l, --loginpass Login/Wrapping passphrase for USER,
- used to wrap MOUNTPASS
- --nopwcheck Do not check the validity of the specified
- login password (useful for LDAP user accounts)
- --noautomount Setup this user such that the encrypted private
- directory is not automatically mounted on login
- --noautoumount Setup this user such that the encrypted private
- directory is not automatically unmounted at
- logout
- -m, --mountpass Passphrase for mounting the ecryptfs directory,
- defaults to randomly generated $KEYBYTES bytes
- -b, --bootstrap Bootstrap a new user's entire home directory
- Generates a random mount passphrase, which
- will be wrapped when the new login passphrase
- is set. SHOULD ONLY BE CALLED FROM 'adduser'.
- --undo Provide instructions on how to undo an
- encrypted private setup
-
- Be sure to properly escape your parameters according to your
- shell's special character nuances, and also surround the
- parameters by double quotes, if necessary.
- "
- exit 1
- }
-
- undo_msg() {
- echo "
- In the event that you want to remove your eCryptfs Private Directory setup,
- you will need to very carefully perform the following actions manually:
-
- 1. Obtain your Private directory mountpoint
- $ PRIVATE=\`cat ~/.ecryptfs/Private.mnt 2>/dev/null || echo \$HOME/$PRIVATE_DIR\`
- 2. Ensure that you have moved all relevant data out of your \$PRIVATE directory
- 3. Unmount your encrypted private directory
- $ ecryptfs-umount-private
- 4. Make your Private directory writable again
- $ chmod 700 \$PRIVATE
- 5. Remove \$PRIVATE, ~/.Private, ~/.ecryptfs
- Note: THIS IS VERY PERMANENT, BE VERY CAREFUL
- $ rm -rf \$PRIVATE ~/.Private ~/.ecryptfs
- 6. Uninstall the utilities (this is specific to your Linux distribution)
- $ sudo apt-get remove ecryptfs-utils libecryptfs0
- "
- }
-
- error() {
- echo `gettext "ERROR:"` "$1" 1>&2
- exit 1
- }
-
- error_testing() {
- rm -f "$1" >/dev/null
- /sbin/umount.ecryptfs_private >/dev/null
- error "$2"
- exit 1
- }
-
- random_passphrase () {
- bytes=$1
- # Pull $1 of random data from /dev/urandom,
- # and convert to a string of hex digits
- od -x -N $bytes --width=$bytes /dev/urandom | head -n 1 | sed "s/^0000000//" | sed "s/\s*//g"
- }
-
- filename_encryption_available() {
- version=$(cat /sys/fs/ecryptfs/version 2>/dev/null)
- [ -z "$version" ] && error `gettext "Can't get ecryptfs version, ecryptfs kernel module not loaded?"`
- [ $(($version & 0x100)) -eq 0 ] && return 1
- return 0
- }
-
- filename_encryption_available && FNEK="--fnek"
-
- if [ ! -z "$SUDO_USER" ]; then
- USER="$SUDO_USER"
- fi
-
- while [ ! -z "$1" ]; do
- case "$1" in
- -u|--username)
- USER="$2"
- shift 2
- ;;
- -l|--loginpass)
- LOGINPASS="$2"
- shift 2
- ;;
- -m|--mountpass)
- MOUNTPASS="$2"
- shift 2
- ;;
- -w|--wrapping)
- WRAPPING_PASS="INDEPENDENT"
- MESSAGE=`gettext "Enter your wrapping passphrase"`
- shift 1
- ;;
- -f|--force)
- FORCE=1
- shift 1
- ;;
- --nopwcheck)
- NOPWCHECK=1
- shift 1
- ;;
- --noautomount)
- NOAUTOMOUNT=1
- shift 1
- ;;
- --noautoumount)
- NOAUTOUMOUNT=1
- shift 1
- ;;
- --undo)
- undo_msg
- exit 0
- ;;
- -b|--bootstrap)
- [ `whoami` = "root" ] || error `gettext "You must be root to bootstrap encrypt a home directory"`
- BOOTSTRAP=1
- MOUNTPASS=`random_passphrase $KEYBYTES`
- RANDOM_MOUNTPASS=1
- shift 1
- ;;
- -n|--no-fnek)
- FNEK=
- shift 1
- ;;
- *)
- usage
- ;;
- esac
- done
-
- # Prompt for the USER name, if not on the command line and not in the env
- if [ -z "$USER" ]; then
- while [ true ]; do
- echo -n gettext `"Enter the username: "`
- USER=`head -n1`
- echo
- if [ -z "$USER" ]; then
- echo `gettext "ERROR: "` `gettext "You must provide a username"`
- continue
- else
- # Verify that the user exists
- if ! id "$USER" >/dev/null; then
- echo `gettext "ERROR: "` `gettext "User does not exist"` " [$USER]"
- continue
- fi
- break
- fi
- done
- else
- # Verify that the user exists
- id "$USER" >/dev/null || error `gettext "User does not exist"` "[$USER]"
- fi
-
- # Obtain USER's primary group
- GROUP=$(id -g $USER)
-
- # Check if the ecryptfs group exists, and user is member of ecryptfs group
- if grep -qs "^ecryptfs:" /etc/group; then
- if ! id "$USER" | grep -qs "\(ecryptfs\)"; then
- error `gettext "User needs to be a member of ecryptfs group"`
- fi
- fi
-
- # Obtain the user's home directory
- HOME=`getent passwd "$USER" | awk -F: '{print $6}'`
- if [ ! -d "$HOME" ]; then
- error `gettext "User home directory does not exist"` "[$HOME]"
- fi
-
- if [ "$BOOTSTRAP" = "1" ]; then
- # If we want to encrypt the entire homedir, we need the .ecryptfs
- # config dir elsewhere, but linked into the homedir
- mkdir -p -m 700 $ECRYPTFS_DIR/$USER/.ecryptfs
- ln -sf $ECRYPTFS_DIR/$USER/.ecryptfs $HOME/.ecryptfs
- ln -sf $ECRYPTFS_DIR/$USER/.$PRIVATE_DIR $HOME/.$PRIVATE_DIR
- MOUNTPOINT="$HOME"
- CRYPTDIR="$ECRYPTFS_DIR/$USER/.$PRIVATE_DIR"
- else
- mkdir -m 700 $HOME/.ecryptfs
- MOUNTPOINT="$HOME/$PRIVATE_DIR"
- CRYPTDIR="$HOME/.$PRIVATE_DIR"
- fi
-
- # Check for previously setup private directory
- if [ -s "$HOME/.ecryptfs/wrapped-passphrase" -a "$FORCE" != "1" ]; then
- error `gettext "wrapped-passphrase file already exists, use --force to overwrite."`
- fi
- if [ -s "$HOME/.ecryptfs/$PRIVATE_DIR.sig" -a "$FORCE" != "1" ]; then
- error "$PRIVATE_DIR.sig" `gettext "file already exists, use --force to overwrite."`
- fi
-
- # Check for active mounts
- grep -qs "$MOUNTPOINT " /proc/mounts && error "[$MOUNTPOINT]" `gettext "is already mounted"`
- grep -qs "$CRYPTDIR " /proc/mounts && error "[$CRYPTDIR]" `gettext "is already mounted"`
-
- # Check that the mount point and encrypted directory are empty (skip symlinks).
- # Perhaps one day we could provide a migration mode (using rsync or something),
- # but this would be VERY hard to do safely.
- count=`ls -Al "$MOUNTPOINT" 2>/dev/null | egrep -c "^[drwx-]{10}"`
- if [ "$count" != "0" ]; then
- error "$MOUNTPOINT" `gettext "must be empty before proceeding"`
- fi
- count=`ls -Al "$CRYPTDIR" 2>/dev/null | egrep -c "^[dlrwx-]{10}"`
- if [ "$count" != "0" ]; then
- error "$CRYPTDIR" `gettext "must be empty before proceeding"`
- fi
-
- stty_orig=`stty -g`
- # Prompt for the LOGINPASS, if not on the command line and not in the env
- if [ -z "$LOGINPASS" ] && [ "$BOOTSTRAP" != "1" ]; then
- tries=0
- while [ $tries -lt $PW_ATTEMPTS ]; do
- stty -echo
- echo -n "$MESSAGE: "
- LOGINPASS=`head -n1`
- stty $stty_orig
- echo
- if [ $WRAPPING_PASS != "LOGIN" -o ! -x /sbin/unix_chkpwd ]; then
- # If we can't check the accuracy of the user's entered
- # passphrase, force them to type it twice (matching)
- stty -echo
- echo -n "$MESSAGE (again): "
- LOGINPASS2=`head -n1`
- stty $stty_orig
- echo
- if [ "$LOGINPASS" != "$LOGINPASS2" ]; then
- echo `gettext "ERROR:"` `gettext "Wrapping passphrases must match"`
- else
- break
- fi
- tries=$(($tries + 1))
- continue
- fi
- if [ -z "$LOGINPASS" ]; then
- echo `gettext "ERROR:"` `gettext "You must provide a login passphrase"`
- tries=$(($tries + 1))
- else
- if [ "$NOPWCHECK" = "1" ]; then
- echo `gettext "INFO:"` `gettext "Skipping password verification"`
- break
- else
- if printf "%s\0" "$LOGINPASS" | /sbin/unix_chkpwd "$USER" nullok; then
- break
- else
- echo `gettext "ERROR:"` `gettext "Your login passphrase is incorrect"`
- tries=$(($tries + 1))
- fi
- fi
- fi
- done
- if [ $tries -ge $PW_ATTEMPTS ]; then
- error `gettext "Too many incorrect password attempts, exiting"`
- fi
- fi
-
- # Prompt for the MOUNTPASS, if not on the command line and not in the env
- if [ -z "$MOUNTPASS" ]; then
- tries=0
- while [ $tries -lt $PW_ATTEMPTS ]; do
- stty -echo
- echo -n `gettext "Enter your mount passphrase [leave blank to generate one]: "`
- MOUNTPASS=`head -n1`
- stty $stty_orig
- echo
- if [ -z "$MOUNTPASS" ]; then
- MOUNTPASS=`random_passphrase $KEYBYTES`
- RANDOM_MOUNTPASS=1
- break
- else
- stty -echo
- echo -n `gettext "Enter your mount passphrase (again): "`
- MOUNTPASS2=`head -n1`
- stty $stty_orig
- echo
- if [ "$MOUNTPASS" != "$MOUNTPASS2" ]; then
- echo `gettext "ERROR:"` `gettext "Mount passphrases do not match"`
- tries=$(($tries + 1))
- else
- break
- fi
- fi
- done
- if [ $tries -ge $PW_ATTEMPTS ]; then
- error `gettext "Too many incorrect passphrase attempts, exiting"`
- fi
- fi
-
- echo
- echo "************************************************************************"
- echo `gettext "YOU SHOULD RECORD YOUR MOUNT PASSPHRASE AND STORE IT IN A SAFE LOCATION."`
- echo " ecryptfs-unwrap-passphrase ~/.ecryptfs/wrapped-passphrase"
- echo `gettext "THIS WILL BE REQUIRED IF YOU NEED TO RECOVER YOUR DATA AT A LATER TIME."`
- echo "************************************************************************"
- echo
-
- ###############################################################################
-
- # Setup private directory in home
- mkdir -m 700 -p "$CRYPTDIR" || error `gettext "Could not create crypt directory"` "[$CRYPTDIR]"
- mkdir -m 700 -p "$MOUNTPOINT" || error `gettext "Could not create mount directory"` "[$MOUNTPOINT]"
- ln -sf /usr/share/ecryptfs-utils/ecryptfs-mount-private.txt "$MOUNTPOINT"/README.txt
- ln -sf /usr/share/ecryptfs-utils/ecryptfs-mount-private.desktop "$MOUNTPOINT"/Access-Your-Private-Data.desktop
- chmod 500 "$MOUNTPOINT"
-
- # Setup ~/.ecryptfs directory
- if [ "$NOAUTOMOUNT" = "1" ]; then
- echo `gettext "INFO:"` "$HOME/$PRIVATE_DIR" `gettext "will not be mounted on login"`
- else
- touch $HOME/.ecryptfs/auto-mount || error `gettext "Could not setup ecryptfs auto-mount"`
- fi
- if [ "$NOAUTOUMOUNT" = "1" ]; then
- echo `gettext "INFO:"` "$HOME/$PRIVATE_DIR" `gettext "will not be unmounted on logout"`
- else
- touch $HOME/.ecryptfs/auto-umount || error `gettext "Could not setup ecryptfs auto-umount"`
- fi
-
- if [ "$WRAPPING_PASS" = "LOGIN" ]; then
- rm -f $HOME/.ecryptfs/wrapping-independent || error `gettext "Could not remove ecryptfs wrapping-independent"`
- else
- touch $HOME/.ecryptfs/wrapping-independent || error `gettext "Could not setup ecryptfs wrapping-independent"`
- fi
-
-
- # Backup any existing wrapped-passphrase or sig files; we DO NOT destroy this
- timestamp=`date +%Y%m%d%H%M%S`
- for i in "$HOME/.ecryptfs/wrapped-passphrase" "$HOME/.ecryptfs/$PRIVATE_DIR.sig"; do
- if [ -s "$i" ]; then
- mv -f "$i" "$i.$timestamp" || error `gettext "Could not backup existing data"` "[$i]"
- fi
- done
-
- # Setup wrapped-passphrase file
- u=`umask`
- umask 377
- if [ "$BOOTSTRAP" = "1" ]; then
- # This will be wrapped by pam_ecryptfs's chauthtok as soon as the user
- # chooses a password. Until that happens (hopefully soon), standard
- # file permissions (600) are all that's protecting it. Write it to
- # ramdisk, to keep it from leaking to the hard-drive.
- temp=`mktemp /dev/shm/.ecryptfs-XXXXXX`
- printf "%s" "$MOUNTPASS" > "$temp"
- mv "$temp" "/dev/shm/.ecryptfs-$USER"
- else
- printf "%s\n%s" "$MOUNTPASS" "$LOGINPASS" | ecryptfs-wrap-passphrase "$HOME/.ecryptfs/wrapped-passphrase" - || error `gettext "Could not wrap passphrase"`
- fi
- umask $u
-
- # Add the passphrase to current keyring
- # On subsequent logins, this should be handled by "pam_ecryptfs.so unwrap"
- response=`printf "%s" "$MOUNTPASS" | ecryptfs-add-passphrase $FNEK -`
- if [ $? -ne 0 ]; then
- error `gettext "Could not add passphrase to the current keyring"`
- fi
- sig=`echo "$response" | grep "Inserted auth tok" | sed "s/^.*\[//" | sed "s/\].*$//"`
- if ! echo "$sig" | egrep -qs "^[0-9a-fA-F]{$KEYBYTES,$KEYBYTES}$"; then
- error `gettext "Could not obtain the key signature"`
- fi
- temp=`mktemp`
- echo "$sig" > "$temp" || error `gettext "Could not create signature file"` "[$HOME/.ecryptfs/$PRIVATE_DIR.sig]"
- mv "$temp" "$HOME/.ecryptfs/$PRIVATE_DIR.sig"
- temp=`mktemp`
- echo "$MOUNTPOINT" > "$temp" || error `gettext "Could not create mountpoint file"` "[$HOME/.ecryptfs/$PRIVATE_DIR.mnt]"
- mv "$temp" "$HOME/.ecryptfs/$PRIVATE_DIR.mnt"
-
- echo
- echo `gettext "Done configuring."`
- echo
-
- # Skip the tests if we're in bootstrap mode, but exit with the encrypted
- # homedir mounted
- if [ "$BOOTSTRAP" = "1" ]; then
- # Force the mount here, since the root user has the key loaded,
- # and the calling 'adduser' is about to copy over /etc/skel
- # NOTE: it is the responsibility of 'adduser' to unmount!
- # And ensure that $USER owns the files/dirs we've created as root
- chown $USER:$GROUP "$CRYPTDIR" /dev/shm/.ecryptfs-$USER
- chown -R $USER:$GROUP $ECRYPTFS_DIR/$USER
- chown -R $USER:$GROUP $MOUNTPOINT
- if [ "$FNEK" = "--fnek" ]; then
- fnek_sig=`tail -n 1 "$HOME/.ecryptfs/$PRIVATE_DIR.sig"`
- sig=`head -n 1 "$HOME/.ecryptfs/$PRIVATE_DIR.sig"`
- sig_opt="ecryptfs_sig=$sig,ecryptfs_fnek_sig=$fnek_sig"
- else
- sig_opt="ecryptfs_sig=$sig"
- fi
- # Do the mount, and provide some helpful symlinks
- mount -i -t ecryptfs -o "rw,$sig_opt,ecryptfs_cipher=$CIPHER,ecryptfs_key_bytes=$KEYBYTES" "$CRYPTDIR" "$MOUNTPOINT" || error "Could not mount"
- ln -sf $ECRYPTFS_DIR/$USER/.ecryptfs $MOUNTPOINT/.ecryptfs
- ln -sf $ECRYPTFS_DIR/$USER/.$PRIVATE_DIR $MOUNTPOINT/.$PRIVATE_DIR
- chown -R $USER:$GROUP $ECRYPTFS_DIR/$USER
- chown -R $USER:$GROUP $MOUNTPOINT
- exit 0
- fi
-
- # Now let's perform some basic mount/write/umount/read sanity testing...
- echo `gettext "Testing mount/write/umount/read..."`
- /sbin/mount.ecryptfs_private || error `gettext "Could not mount private ecryptfs directory"`
- temp=`mktemp "$MOUNTPOINT/ecryptfs.test.XXXXXX"` || error_testing "$temp" `gettext "Could not create empty file"`
- random_data=`head -c 16000 /dev/urandom | od -x` || error_testing "$temp" `gettext "Could not generate random data"`
- echo "$random_data" > "$temp" || error_testing "$temp" `gettext "Could not write encrypted file"`
- md5sum1=`md5sum "$temp"` || error_testing "$temp" `gettext "Could not read encrypted file"`
- /sbin/umount.ecryptfs_private || error_testing "$temp" `gettext "Could not unmount private ecryptfs directory"`
- /sbin/mount.ecryptfs_private || error_testing "$temp" `gettext "Could not mount private ecryptfs directory (2)"`
- md5sum2=`md5sum "$temp"` || error_testing "$temp" `gettext "Could not read encrypted file (2)"`
- rm -f "$temp"
- # Use ecryptfs-umount-private on the final run, to clear the used keys
- # out of the keyring
- ecryptfs-umount-private || error_testing "$temp" `gettext "Could not unmount private ecryptfs directory (2)"`
- if [ "$md5sum1" != "$md5sum2" ]; then
- error `gettext "Testing failed."`
- else
- echo `gettext "Testing succeeded."`
- fi
-
- echo
- echo `gettext "Logout, and log back in to begin using your encrypted directory."`
- echo
- exit 0
-